package com.lxj.network.http;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.SyncBasicHttpContext;
import org.apache.http.util.EntityUtils;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;




import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestHandle;
import com.loopj.android.http.RequestParams;
import com.loopj.android.http.SyncHttpClient;
import com.lxj.utils.L;
import com.lxj.utils.ZlibUtils;

public class HttpUtils 
{
    public static String COMPRESSION_CONTENT_TYPE = "application/octet-stream";
    public static String TAG = "HttpUtils";
    
    private static int ERROR_CODE = 0;

    private static final int TRY_MAX_TIMES = 5;
    private static final int TRY_SLEEP_TIME = 200;
    
    static RetryHandler mRetryHandler = new RetryHandler(TRY_MAX_TIMES, TRY_SLEEP_TIME);
    static SyncBasicHttpContext httpContext = new SyncBasicHttpContext(new BasicHttpContext());

    public static String URLEncoder(String aString)
    {
            String ret = null;
            if (aString != null)
            {
                    try {
						ret = java.net.URLEncoder.encode(aString, "UTF-8");
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					}
            }
            return ret;
    }

    public static String URLDecoder(String aString)
    {
            String ret = null;
            if (aString != null)
            {
                try {
					ret = java.net.URLDecoder.decode(aString, "UTF-8");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
            }
            return ret;
    }
    
    private static AsyncHttpClient mAsyncHttpClient = null;
    
    public static synchronized RequestHandle get(Context aContext, String url, RequestParams params, AsyncHttpResponseHandler responseHandler)
    {
    	String requesturl = url;
    	if(params != null)
    	{
    		requesturl = AsyncHttpClient.getUrlWithQueryString(true, url, params);
    	}
    	
    	L.e(TAG + ".get()", requesturl);
    	if(mAsyncHttpClient == null)
    	{
        	mAsyncHttpClient = new AsyncHttpClient();
    	}
    	
    	return mAsyncHttpClient.get(aContext, url, params, responseHandler);
    }
    
    public static synchronized RequestHandle post(Context aContext, String url, RequestParams params, byte[] aPostData, String contentType, AsyncHttpResponseHandler responseHandler)
    {
    	String requesturl = url;
    	if(params != null)
    	{
    		requesturl = AsyncHttpClient.getUrlWithQueryString(true, url, params);
    	}
    	
    	L.e(TAG + ".post()", requesturl);
    	ByteArrayEntity entity = new ByteArrayEntity(aPostData);
    	
    	if(mAsyncHttpClient == null)
    	{
        	mAsyncHttpClient = new AsyncHttpClient();
    	}
    	return mAsyncHttpClient.post(aContext, requesturl, entity, contentType, responseHandler);
    }
    
    static HttpClient httpClient = null;
	public static synchronized HttpClient getHttpClient() {
		int DEFAULT_SOCKET_TIMEOUT = 10000;
		int DEFAULT_MAX_CONNECTIONS = 8;
		int DEFAULT_HOST_CONNECTIONS = 8;
		int DEFAULT_SOCKET_BUFFER_SIZE = 20480;
		if (httpClient == null) {
			final HttpParams httpParams = new BasicHttpParams();
			ConnManagerParams.setTimeout(httpParams, 1000);
			HttpConnectionParams.setConnectionTimeout(httpParams,
					DEFAULT_SOCKET_TIMEOUT);
			HttpConnectionParams.setSoTimeout(httpParams,
					DEFAULT_SOCKET_TIMEOUT);
			ConnManagerParams.setMaxConnectionsPerRoute(httpParams,
					new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS));
			ConnManagerParams.setMaxTotalConnections(httpParams,
					DEFAULT_MAX_CONNECTIONS);
			HttpProtocolParams.setUseExpectContinue(httpParams, true);
			HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
			HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
			HttpClientParams.setRedirecting(httpParams, false);
			HttpConnectionParams.setTcpNoDelay(httpParams, true);
			HttpConnectionParams.setSocketBufferSize(httpParams,
					DEFAULT_SOCKET_BUFFER_SIZE);
			SchemeRegistry schemeRegistry = new SchemeRegistry();
			schemeRegistry.register(new Scheme("http", PlainSocketFactory
					.getSocketFactory(), 80));
			schemeRegistry.register(new Scheme("https", SSLSocketFactory
					.getSocketFactory(), 443));
			ClientConnectionManager manager = new ThreadSafeClientConnManager(
					httpParams, schemeRegistry);
			httpClient = new DefaultHttpClient(manager, httpParams);
		}
		return httpClient;
	}
    
    public static byte[] GetDataFromUrlByPostData(String httpurl, byte[] aData, String aContentType) throws Exception
    {
    	ERROR_CODE = 0;
            if (httpurl == null)
            {
                    return null;
            }
            L.e("GetDataFromUrlByPostData", httpurl);

            byte[] retstr = null;
            
        	Exception myException = null;
        	int executionCount = 0;
        	boolean needtry = true;
        	IOException cause = null;
        	while(needtry)
        	{
                try
                {
                        HttpClient httpclient = getHttpClient();

                        HttpResponse response = null;
                        HttpPost mCurrentHttpPost = new HttpPost(httpurl);
                        mCurrentHttpPost.setEntity(new ByteArrayEntity(aData));
                        if (aContentType != null)
                        {
                                mCurrentHttpPost.setHeader("Content-Type", aContentType);
                        }
                        response = httpclient.execute(mCurrentHttpPost);

                        int statuscode = -1;
                        if(response != null)
                        {
                        	statuscode = response.getStatusLine().getStatusCode();
                        }

                        if (statuscode == HttpStatus.SC_OK)
                        {
                                retstr = EntityUtils.toByteArray(response.getEntity());

                                if (iSResponseNeedDecompress(response))
                                {
                                        retstr = ZlibUtils.decompress(retstr);
                                }
                                break;
                        }
                }
                catch (UnknownHostException e) {
                    // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException
                    // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry
                    // (to assist in genuine cases of unknown host) which seems better than outright failure
                    cause = new IOException("UnknownHostException exception: " + e.getMessage());
                    needtry = (executionCount > 0) && mRetryHandler.retryRequest(cause, ++executionCount, httpContext);
                } catch (NullPointerException e) {
                    // there's a bug in HttpClient 4.0.x that on some occasions causes
                    // DefaultRequestExecutor to throw an NPE, see
                    // http://code.google.com/p/android/issues/detail?id=5255
                	myException = new IOException("NPE in HttpClient: " + e.getMessage());
                    needtry = mRetryHandler.retryRequest(cause, ++executionCount, httpContext);
                } catch (IOException e) {
                    myException = e;
                    needtry = mRetryHandler.retryRequest(cause, ++executionCount, httpContext);
                }
        	}
        	
        	if(myException != null)
        	{
        		throw myException;
        	}
            return retstr;
    }


    public static boolean iSResponseNeedDecompress(HttpResponse aResponse)
    {
            boolean ret = false;
            if (aResponse != null)
            {
                    Header head = aResponse.getEntity().getContentType();
                    HeaderElement[] headvalue = head.getElements();
                    if (headvalue != null && headvalue.length > 0)
                    {
                            String ContentType = headvalue[0].toString();
                            if (ContentType.equals(COMPRESSION_CONTENT_TYPE))
                            {
                                    ret = true;
                            }
                            else if (ContentType.equals("text/javascript"))
                            {
                                    ret = false;
                            }
                    }
            }
            return ret;
    }


    public static boolean iSResponseNeedDecompress(Header[] headers)
    {
            boolean ret = false;
            if (headers != null && headers.length > 0)
            {
            	for(Header theader : headers)
            	{
            		String info = theader.toString();
            		if(info.contains(COMPRESSION_CONTENT_TYPE))
            		{
            			ret = true;
            			break;
            		}
            	}
            }
            return ret;
    }
    
    private static byte[] retstr = null;

    public synchronized static byte[] GetDataFromUrl(String httpurl) throws Exception
    {
    	retstr = null;
    	ERROR_CODE = 0;
    	L.e("GetDataFromUrl", httpurl);
    	SyncHttpClient asyncHttpClient = new SyncHttpClient();
    	
    	asyncHttpClient.get(httpurl, new AsyncHttpResponseHandler() {

    		@Override
    		public void onRetry() {
    			super.onRetry();
    			L.e("SyncHttpClient", "onRetry");
    		}
    		@Override
    		public void onStart() {
    			super.onStart();
    			L.e("SyncHttpClient", "onStart");
    		}
    		
    		@Override
    		public void onFinish() {
    			super.onFinish();
    			L.e("SyncHttpClient", "onFinish");
    		}
    		@Override
    		public void onProgress(int bytesWritten, int totalSize) {
    			super.onProgress(bytesWritten, totalSize);
    			L.e("SyncHttpClient", "bytesWritten:" + bytesWritten);
    			L.e("SyncHttpClient", "totalSize:" + totalSize);
    		}
    		
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {
            	if (iSResponseNeedDecompress(headers))
                {
            		retstr = ZlibUtils.decompress(binaryData);
                }
            	else
            	{
            		retstr = binaryData;
            	}
    			L.e("SyncHttpClient", "onSuccess");
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {

            	ERROR_CODE = -1;
    			L.e("SyncHttpClient", "onFailure");
            }
		});


    	while(ERROR_CODE == 0)
    	{
    		if(retstr != null)
    		{
    			break;
    		}
    		Thread.sleep(50);
    	}
    	
//    	
//      if (httpurl == null)
//      {
//              return null;
//      }
//      L.e("GetDataFromUrl", httpurl);
//  	ERROR_CODE= 0;
//
//      byte[] retstr = null;
//      
//        	Exception myException = null;
//        	int executionCount = 0;
//        	boolean needtry = true;
//        	IOException cause = null;
//        	
//        	while(needtry)
//        	{
//                try
//                {
//                	executionCount++;
//                	HttpClient httpclient = getHttpClient();
//                    HttpResponse response = null;
//                    HttpGet mCurrentHttpGet = new HttpGet(httpurl);
//                           
//                    response = httpclient.execute(mCurrentHttpGet);
//
//                    int statuscode = -1;
//                    if(response != null)
//                    {
//                    	statuscode = response.getStatusLine().getStatusCode();
//                    }
//
//                    if (statuscode == HttpStatus.SC_OK)
//                    {
//                            retstr = EntityUtils.toByteArray(response.getEntity());
//
//                            if (iSResponseNeedDecompress(response))
//                            {
//                                    retstr = decompress(retstr);
//                            }
//                            break;
//                    }
//                }
//                catch (UnknownHostException e) {
//                    // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException
//                    // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry
//                    // (to assist in genuine cases of unknown host) which seems better than outright failure
//                    cause = new IOException("UnknownHostException exception: " + e.getMessage());
//                    needtry = (executionCount > 0) && mRetryHandler.retryRequest(cause, ++executionCount, httpContext);
//                } catch (NullPointerException e) {
//                    // there's a bug in HttpClient 4.0.x that on some occasions causes
//                    // DefaultRequestExecutor to throw an NPE, see
//                    // http://code.google.com/p/android/issues/detail?id=5255
//                	myException = new IOException("NPE in HttpClient: " + e.getMessage());
//                    needtry = mRetryHandler.retryRequest(cause, ++executionCount, httpContext);
//                } catch (IOException e) {
//                    myException = e;
//                    needtry = mRetryHandler.retryRequest(cause, ++executionCount, httpContext);
//                }
//        	}
//        	
//    	if(myException != null)
//    	{
//    		throw myException;
//    	}
        return retstr;
    }
    
    public static int getErrorCode()
    {
    	return ERROR_CODE;
    }


    public static String GetPostContentType()
    {
            return "multipart/form-data; boundary=7dbfa4406b6";
    }
    
    public static String GetPostUnBinaryContentType()
    {
            return "application/x-www-form-urlencoded";
    }
    public static byte[] GetPostUnBinaryContent(boolean isFirstParameter, String aContentName, String aContentData)
    {
            String ret = (isFirstParameter ? "" : "&") + aContentName + "=" + aContentData; 
            return ret.getBytes();
    }

    public static byte[] GetPostHead()
    {
            return "\r\n".getBytes();
    }

    public static byte[] GetPostContent(String aContentName, String aContentType, byte[] aContentData)
    {
            if (aContentData != null && aContentName != null)
            {
                    byte[] head = null;

                    if (aContentType != null)
                    {
                            head = ("\r\n--7dbfa4406b6\r\nContent-Disposition: form-data; name=\"" + aContentName + "\";filename=\"2.jpg\"\r\nContent-Type: " + aContentType + "\r\n\r\n").getBytes();
                    }
                    else
                    {
                            head = ("\r\n--7dbfa4406b6\r\nContent-Disposition: form-data; name=\"" + aContentName + "\"\r\n\r\n").getBytes();
                    }
                    byte[] retdata = new byte[head.length + aContentData.length];
                    int offset = 0;
                    System.arraycopy(head, 0, retdata, offset, head.length);
                    offset += head.length;
                    System.arraycopy(aContentData, 0, retdata, offset, aContentData.length);
                    offset += aContentData.length;
                    return retdata;
            }
            else
            {
                    return null;
            }
    }
    public static final int APNTYPE_NONE = 1;   
    public static final int APNTYPE_MOBILE = 2;   
    public static final int APNTYPE_WIFI = 3; 
    
	public static int getAPNType(Context context) {
		int netType = APNTYPE_NONE;
		ConnectivityManager connMgr = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();

		if (networkInfo == null) {
			return netType;
		}
		int nType = networkInfo.getType();
		System.out.println("networkInfo.getExtraInfo() is "+ networkInfo.getExtraInfo());
		if (nType == ConnectivityManager.TYPE_MOBILE) {
			netType = APNTYPE_MOBILE;
		} else if (nType == ConnectivityManager.TYPE_WIFI) {
			netType = APNTYPE_WIFI;
		} 
		return netType;
	}

    public static boolean isNetConnect(Context context)
    {
            boolean ret = false;
            try
            {
                    ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                    if (connectivity != null)
                    {
                            NetworkInfo info = connectivity.getActiveNetworkInfo();
                            if (info != null && info.isConnected())
                            {
                                    if (info.getState() == NetworkInfo.State.CONNECTED)
                                    {
                                            ret = true;
                                    }
                            }
                    }
            }
            catch (Exception e)
            {
                    ret = false;
            }
            return ret;
    }

    public static byte[] GetPostEnd()
    {
            return "\r\n--7dbfa4406b6--".getBytes();
    }
}
